package main

import "fmt"

// RetrUID retrieves the item (whether a Node, Label, Field, or Relation)
// specified by the given UID.
func (lex *Lexicon) RetrUID(uid UID) (interface{}, error) {
	if i, ok := lex.Nodes[uid]; ok {
		return i, nil
	} else if i, ok := lex.Labels[uid]; ok {
		return i, nil
	} else if i, ok := lex.Fields[uid]; ok {
		return i, nil
	} else if i, ok := lex.Relations[uid]; ok {
		return i, nil
	}
	return nil, fmt.Errorf("Item not found for UID %s", uid)
}

// RetrSlug retrieves the item (whether a Node, Label, Field, or Relation)
// specified by the given slug.
func (lex *Lexicon) RetrSlug(slug string) (interface{}, error) {
	uid, defined := lex.Slugs[slug]
	if !defined {
		return nil, fmt.Errorf("Item not found for slug %q", slug)
	}
	return lex.RetrUID(uid)
}

/* ********************************** */

func newLexicon() *Lexicon {
	return &Lexicon{
		Nodes:     make(map[UID]*Node),
		Labels:    make(map[UID]*Label),
		Fields:    make(map[UID]*Field),
		Relations: make(map[UID]*Relation),
		Slugs:     make(map[string]UID),
	}
}

func (lex *Lexicon) init() {
	// set up for new UID creation
	nuids := make(chan UID)
	lex.newUID = nuids
	go func() {
		for {
			nuids <- lex.NUID
			lex.NUID++
		}
	}()

	// add reference to lex in all nodes
	for _, n := range lex.Nodes {
		n.Lexicon = lex
	}
}

/* ********************************** */

func (lex *Lexicon) forget(uid UID) {
	item, err := lex.RetrUID(uid)
	if err != nil {
		// Nothing to remove
		return
	}

	switch e := item.(type) {
	case Node:
		delete(lex.Nodes, uid)
		lex.forget(e.Label)
	case Label:
		delete(lex.Labels, uid)
		delete(lex.Slugs, e.Slug)
	case Field:
		delete(lex.Fields, uid)
		lex.forget(e.Label)
	case Relation:
		delete(lex.Relations, uid)
		lex.forget(e.Label)
	default:
	}

}
